<?php

/**
 * This file is part of the Codizer package.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @copyright   Copyright (c) 2010 Advisa (http://www.advisa.fr)
 * @author      Codizer Core Team <team@codizer.org>
 * @package     Codizer
 */

class f_mail_Message
{
    private $from;
    private $returnPath;
    private $to;
    private $subject;
    private $bodyText;
    private $bodyHtml;
    private $frontier;
    private $attachment;
    private static $line = "\n";
    private static $dualLine = "\n\n";

    /**
     * Constructor
     */
    private function __construct()
    {
        $this->frontier = md5(uniqid(mt_rand()));
    }

    /**
     * Get a new instance
     *
     * @return f_mail_Message
     */
    public static function getInstance()
    {
        return new self();
    }

    /**
     * Set the sender
     *
     * @param string $emailAddress
     * @param string $name (optionnal)
     * @return f_mail_Message
     */
    public function setFrom($emailAddress, $name = null)
    {
        $value = !is_null($name) ? $name.' <'.$emailAddress.'>':$emailAddress;
        $this->from = $value;
        $this->returnPath = $emailAddress;
        return $this;
    }

    /**
     * Set the receiver(s)
     *
     * @example setTo('name1@domain.tld', 'name2@domain.tld')
     * @param string(s) (comma separated)
     * @return f_mail_Message
     */
    public function setTo()
    {
        $args = func_get_args();

        if (count($args) > 0)
        {
            foreach ($args as $arg)
            {
                $this->to[] = $arg;
            }
        }

        return $this;
    }

    /**
     * Set the mail subject
     *
     * @param string $value
     * @return f_mail_Message
     */
    public function setSubject($value)
    {
        $this->subject = $value;
        return $this;
    }

    /**
     * Set mail body (textual)
     *
     * @param string $value
     * @return f_mail_Message
     */
    public function setBodyText($value)
    {
        $this->bodyText = $value;
        return $this;
    }

    /**
     * Set mail body (html)
     *
     * @param string $value
     * @return f_mail_Message
     */
    public function setBodyHtml($value)
    {
        $this->bodyHtml = $value;
        return $this;
    }

    /**
     * Add a file with the mail
     *
     * @param string $attachment
     * @param string $mimeType
     * @return f_mail_Message
     */
    public function addAttachment($attachment, $mimeType)
    {
        $a['mimeType'] = $mimeType;
        $a['file'] = $attachment;
        $this->attachment[] = $a;
        return $this;
    }

    /**
     * The mail has a file in it ?
     *
     * @return boolean
     */
    private function hasAttachment()
    {
        return isset($this->attachment) && count($this->attachment) > 0;
    }

    /**
     * Send the mail
     *
     * @return boolean
     */
    public function send($useReturnPath = true)
    {
        if (($this->bodyText != '' || $this->bodyHtml != '') && isset($this->to) && isset($this->from))
        {
            if(version_compare(phpversion(), '5.3.0', '>=') || ini_get("safe_mode") || $useReturnPath == false)
            {
                return mail(join(',', $this->to), $this->subject, $this->buildMessage(), $this->buildHeader());
            }
            else
            {
                return mail(join(',', $this->to), $this->subject, $this->buildMessage(), $this->buildHeader(), '-f'.$this->returnPath);
            }
        }
        return false;
    }

    /**
     * Build the mail header
     * 
     * @return string
     */
    private function buildHeader()
    {
        $header = 'From: ' . $this->from . self::$line;
        $header .= 'Reply-To: ' . $this->from . self::$line;
        $header .= 'X-Sender: ' . $this->from . self::$line;
        $header .= 'X-Mailer:PHP/' . phpversion() . self::$line;

        if ($this->isMultiPart() || $this->hasAttachment())
        {
            $header .= 'MIME-Version: 1.0' . self::$line;
        }

        if ($this->hasAttachment())
        {
            $header .= 'Content-Type: multipart/mixed; boundary="multi-' . $this->frontier . '"' . self::$line;
        }
        else
        {
            if ($this->isMultiPart())
            {
                $header .= 'Content-Type: multipart/alternative; boundary="alt-' . $this->frontier . '"' . self::$line;
            }
            else if (isset($this->bodyText) && !is_null($this->bodyText))
            {
                $header .= 'Content-Type: text/plain; charset="utf-8"' . self::$line;
            }
            else
            {
                $header .= 'Content-Type: text/html; charset="utf-8"' . self::$line;
            }
        }

        $header .= 'Content-Transfer-Encoding: base64' . self::$dualLine;

        return $header;
    }

    /**
     * Build the mail message
     *
     * @return string
     */
    private function buildMessage()
    {
        $message = '';

        if ($this->isMultiPart())
        {

            if ($this->hasAttachment())
            {
                $message .= '--multi-' . $this->frontier . self::$line;
                $message .= 'Content-Type: multipart/alternative; boundary="alt-' . $this->frontier . '"' . self::$line;
            }

            $message .= '--alt-' . $this->frontier . self::$line;
            $message .= 'Content-Type: text/plain; charset="utf-8"' . self::$line;
            $message .= 'Content-Transfer-Encoding: base64' . self::$dualLine;
            $message .= chunk_split(base64_encode($this->bodyText)) . self::$dualLine;
            
            $message .= '--alt-' . $this->frontier . self::$line;
            $message .= 'Content-Type: text/html; charset="utf-8"' . self::$line;
            $message .= 'Content-Transfer-Encoding: base64' . self::$dualLine;
            $message .= chunk_split(base64_encode($this->bodyHtml)) . self::$dualLine;
        }
        else if (isset($this->bodyText) && !is_null($this->bodyText))
        {
            if ($this->hasAttachment())
            {
                $message .= '--multi-' . $this->frontier . self::$line;
                $message .= 'Content-Type: text/plain; charset="utf-8"' . self::$line;
                $message .= 'Content-Transfer-Encoding: base64' . self::$dualLine;
            }

            $message .= chunk_split(base64_encode($this->bodyText));
        }
        else
        {
            if ($this->hasAttachment())
            {
                $message .= '--multi-' . $this->frontier . self::$line;
                $message .= 'Content-Type: text/html; charset="utf-8"' . self::$line;
                $message .= 'Content-Transfer-Encoding: base64' . self::$dualLine;
            }
            
            $message .= chunk_split(base64_encode($this->bodyHtml));
        }

        if ($this->hasAttachment())
        {
            foreach ($this->attachment as $attachment)
            {
                $fileName = basename($attachment['file']);

                $message .= '--multi-' . $this->frontier . self::$line;
                $message .= 'Content-Type: ' . $attachment['mimeType'] . '; name="' . $fileName . '"' . self::$line;
                $message .= 'Content-Transfer-Encoding: base64' . self::$line;
                $message .= 'Content-Disposition:attachement; filename="' . $fileName . '"' . self::$line;
                $message .= chunk_split(base64_encode(file_get_contents($attachment['file'])));
            }
        }

        return $message;
    }

    /**
     * Check if mail is in text AND html
     *
     * @return boolean
     */
    private function isMultiPart()
    {
        return isset($this->bodyText) && isset($this->bodyHtml) && !is_null($this->bodyText) && !is_null($this->bodyHtml);
    }
}